package com.cinema.service;

import com.cinema.dao.MovieDao;
import com.cinema.dao.ScheduleDao;
import com.cinema.dao.TicketDao;
import com.cinema.dao.impl.MovieDaoImpl;
import com.cinema.dao.impl.ScheduleDaoImpl;
import com.cinema.dao.impl.TicketDaoImpl;
import com.cinema.model.Movie;
import com.cinema.model.Schedule;
import com.cinema.model.Ticket;
import com.cinema.model.TicketType;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 票务服务类
 * 处理售票和退票相关的业务逻辑
 */
public class TicketService {
    private final TicketDao ticketDao;
    private final ScheduleDao scheduleDao;
    private final MovieDao movieDao;

    public TicketService() {
        this.ticketDao = new TicketDaoImpl();
        this.scheduleDao = new ScheduleDaoImpl();
        this.movieDao = new MovieDaoImpl();
    }

    /**
     * 售票
     */
    public List<Ticket> sellTickets(String scheduleId, List<int[]> seats, List<TicketType> ticketTypes) {
        Optional<Schedule> scheduleOpt = scheduleDao.findById(scheduleId);
        if (!scheduleOpt.isPresent()) {
            return null;
        }

        Schedule schedule = scheduleOpt.get();
        Optional<Movie> movieOpt = movieDao.findById(schedule.getMovieId());
        if (!movieOpt.isPresent()) {
            return null;
        }

        Movie movie = movieOpt.get();
        List<Ticket> tickets = new ArrayList<>();

        // 检查所有座位是否可用
        for (int[] seat : seats) {
            int row = seat[0];
            int col = seat[1];
            if (!schedule.isSeatAvailable(row, col)) {
                return null; // 有座位不可用，售票失败
            }
        }

        // 预订所有座位并创建票务
        for (int i = 0; i < seats.size(); i++) {
            int[] seat = seats.get(i);
            int row = seat[0];
            int col = seat[1];
            TicketType ticketType = i < ticketTypes.size() ? ticketTypes.get(i) : TicketType.ADULT;

            // 预订座位
            if (schedule.bookSeat(row, col)) {
                // 计算票价
                double price = calculateTicketPrice(schedule.getPrice(), ticketType, schedule.getShowTime());
                
                // 创建票务
                Ticket ticket = new Ticket(scheduleId, movie.getTitle(), schedule.getHallId(), 
                                         schedule.getShowTime(), row, col, price, ticketType);
                tickets.add(ticket);
                ticketDao.save(ticket);
            } else {
                // 如果预订失败，回滚之前的操作
                for (Ticket ticket : tickets) {
                    schedule.cancelSeat(ticket.getSeatRow(), ticket.getSeatCol());
                    ticketDao.deleteById(ticket.getTicketId());
                }
                return null;
            }
        }

        // 更新场次信息
        scheduleDao.update(schedule);
        return tickets;
    }

    /**
     * 退票
     */
    public boolean refundTicket(String ticketId) {
        Optional<Ticket> ticketOpt = ticketDao.findById(ticketId);
        if (!ticketOpt.isPresent()) {
            return false;
        }

        Ticket ticket = ticketOpt.get();
        if (!ticket.canRefund()) {
            return false; // 不满足退票条件
        }

        // 释放座位
        Optional<Schedule> scheduleOpt = scheduleDao.findById(ticket.getScheduleId());
        if (scheduleOpt.isPresent()) {
            Schedule schedule = scheduleOpt.get();
            schedule.cancelSeat(ticket.getSeatRow(), ticket.getSeatCol());
            scheduleDao.update(schedule);
        }

        // 标记票务为已退票
        ticket.setRefunded(true);
        return ticketDao.update(ticket);
    }

    /**
     * 根据票号查找票务
     */
    public Optional<Ticket> findTicketById(String ticketId) {
        return ticketDao.findById(ticketId);
    }

    /**
     * 获取指定场次的所有票务
     */
    public List<Ticket> getTicketsBySchedule(String scheduleId) {
        return ticketDao.findByScheduleId(scheduleId);
    }

    /**
     * 获取当日销售数据
     */
    public SalesData getTodaySales() {
        LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        LocalDateTime tomorrow = today.plusDays(1);
        return calculateSalesData(today, tomorrow);
    }

    /**
     * 获取当周销售数据
     */
    public SalesData getWeekSales() {
        LocalDateTime weekStart = LocalDateTime.now().minusDays(LocalDateTime.now().getDayOfWeek().getValue() - 1)
                                               .withHour(0).withMinute(0).withSecond(0);
        LocalDateTime weekEnd = weekStart.plusWeeks(1);
        return calculateSalesData(weekStart, weekEnd);
    }

    /**
     * 获取当月销售数据
     */
    public SalesData getMonthSales() {
        LocalDateTime monthStart = LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
        LocalDateTime monthEnd = monthStart.plusMonths(1);
        return calculateSalesData(monthStart, monthEnd);
    }

    /**
     * 计算销售数据
     */
    private SalesData calculateSalesData(LocalDateTime startDate, LocalDateTime endDate) {
        List<Ticket> tickets = ticketDao.findByDateRange(startDate, endDate);
        
        int totalSoldTickets = 0;
        double totalSalesAmount = 0.0;
        int totalRefundedTickets = 0;
        double totalRefundAmount = 0.0;

        for (Ticket ticket : tickets) {
            if (ticket.isRefunded()) {
                totalRefundedTickets++;
                totalRefundAmount += ticket.calculateRefundAmount();
            } else {
                totalSoldTickets++;
                totalSalesAmount += ticket.getPrice();
            }
        }

        return new SalesData(totalSoldTickets, totalSalesAmount, totalRefundedTickets, totalRefundAmount);
    }

    /**
     * 计算票价
     */
    private double calculateTicketPrice(double basePrice, TicketType ticketType, LocalDateTime showTime) {
        double price = basePrice * ticketType.getDiscountRate();
        
        // 早场优惠（上午10点场次打9折）
        if (showTime.getHour() == 10) {
            price *= 0.9;
        }

        return Math.round(price * 100.0) / 100.0; // 保留两位小数
    }

    /**
     * 显示座位图
     */
    public void displaySeatMap(String scheduleId) {
        Optional<Schedule> scheduleOpt = scheduleDao.findById(scheduleId);
        if (!scheduleOpt.isPresent()) {
            System.out.println("场次不存在！");
            return;
        }

        Schedule schedule = scheduleOpt.get();
        boolean[][] seatStatus = schedule.getSeatStatus();
        
        // 检查座位状态矩阵是否为null
        if (seatStatus == null || schedule.getRows() == 0 || schedule.getCols() == 0) {
            System.out.println("座位图信息不可用。");
            System.out.println("总座位数：" + schedule.getTotalSeats());
            System.out.println("可用座位数：" + schedule.getAvailableSeats());
            return;
        }
        
        System.out.println("\n座位图（● = 可用，✖ = 已售出）：");
        System.out.print("   ");
        for (int col = 0; col < schedule.getCols(); col++) {
            System.out.printf("%2d ", col + 1);
        }
        System.out.println();

        for (int row = 0; row < schedule.getRows(); row++) {
            System.out.printf("%2d ", row + 1);
            for (int col = 0; col < schedule.getCols(); col++) {
                System.out.print(seatStatus[row][col] ? " ✖ " : " ● ");
            }
            System.out.println();
        }
        System.out.println("\n总座位数：" + schedule.getTotalSeats());
        System.out.println("可用座位数：" + schedule.getAvailableSeats());
    }

    /**
     * 销售数据内部类
     */
    public static class SalesData {
        private final int totalSoldTickets;
        private final double totalSalesAmount;
        private final int totalRefundedTickets;
        private final double totalRefundAmount;

        public SalesData(int totalSoldTickets, double totalSalesAmount, int totalRefundedTickets, double totalRefundAmount) {
            this.totalSoldTickets = totalSoldTickets;
            this.totalSalesAmount = totalSalesAmount;
            this.totalRefundedTickets = totalRefundedTickets;
            this.totalRefundAmount = totalRefundAmount;
        }

        public int getTotalSoldTickets() {
            return totalSoldTickets;
        }

        public double getTotalSalesAmount() {
            return totalSalesAmount;
        }

        public int getTotalRefundedTickets() {
            return totalRefundedTickets;
        }

        public double getTotalRefundAmount() {
            return totalRefundAmount;
        }

        public double getNetSalesAmount() {
            return totalSalesAmount - totalRefundAmount;
        }

        @Override
        public String toString() {
            return String.format("销售数据：\n" +
                              "售出票数：%d 张\n" +
                              "销售金额：%.2f 元\n" +
                              "退票数：%d 张\n" +
                              "退票金额：%.2f 元\n" +
                              "净销售额：%.2f 元",
                              totalSoldTickets, totalSalesAmount, totalRefundedTickets, totalRefundAmount, getNetSalesAmount());
        }
    }
}